<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8">
    <title>Sucha's Blog - Archive for February, 2022</title>
    <meta name="generator" content="MarkdownProjectCompositor.lua">
    <meta name="author" content="Sucha">
    <meta name="keywords" content="suchang, programming, Linux, Lua">
    <meta name="description" content="Sucha's blog">
    <link rel="shortcut icon" href="../images/ico.png">
    <link rel="stylesheet" type="text/css" href="../styles/blog.css">
    <link rel="stylesheet" type="text/css" href="../styles/prism.min.css">
    <style id="site_theme"></style>
  </head>
  <body>
    <div id="body">
      <div id="text">
	   <!-- Page published by cmark-gfm begins here --><h1>Sucha's Blog ~ Archive for February, 2022</h1>
<p><a id="p2"></a></p>
<div class="date">22年2月27日 周日 23:24</div>
<h2>本站支持代码高亮</h2>
<p>用的方案是 <a href="https://prismjs.com/">Prism</a>，cmark-gfm 本来就支持生成相关的 pre、code tag，并带上 &quot;language-css&quot; 这样的 attribute 值，那只要简单加上下面两行就好了，在项目站点上，选了几个自己觉得也许会用得比较多的语言，比如 Bash/Shell/JS/Lua/Go/Swift/Lisp，我也就大概会这么多而已吧。</p>
<pre><code class="language-html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;../styles/prism.min.css&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;../js/prism.min.js&quot;&gt;&lt;/script&gt;
</code></pre>
<p>感觉效果很不错的，比如之前</p>
<ul>
<li><a href="../blog/2008-06.html#p1">Emacs-Lisp</a></li>
<li><a href="../blog/2021-11.html#p4">Javascript</a></li>
<li><a href="../blog/2021-11.html#p0">Ini</a></li>
<li><a href="../blog/2021-08.html#p0">Lua</a></li>
<li><a href="../blog/2020-12.html#p0">Swift</a></li>
<li><a href="../blog/2020-11.html#p0">Go</a></li>
<li><a href="../blog/2020-09.html#p1">Rust</a></li>
</ul>
<p>选的主题是 tomorrow night，跟已有的主题搭配起来也挺不错，缺点可能是 js 代码 minify 后仍然有 60k 吧。</p>
<p>不管怎么说，还有 Etag 撑着呢，另外，毕竟是存放在 github 的，算是白嫖了。</p>
<div class="category"><a href="CategoryThisSite.html">CategoryThisSite</a> / <a href="2022-02.html#p2">Permalink</a> / <a href="https://github.com/lalawue/homepage/discussions/categories/blog" target="_blank">Discussion</a></div>
<p><a id="p1"></a></p>
<div class="date">22年2月27日 周日 22:35</div>
<h2>MNet 支持 TLS 插件</h2>
<p>先说一下背景，<a href="https://github.com/lalawue/m_net/">mnet</a> 很早就想着加入 TLS 的支持，比如在做 cincau 或者 rpc_framework 的时候，就分别有作为独立 server 支持 https，以及作为 agent 使用内建的 TCP，去请求一个 https 认证的 API，或者拉取网页这样的要求。</p>
<p>但之前都是在 Lua/LuaJIT 这一层，在 C 之外做的 SSL 的状态管理，用起来不稳定，就放弃了，直接用了 curl。当时没有认真研究，自从考虑在 C 这一层，mnet 这一层加入 <a href="https://github.com/lalawue/m_net/tree/master/extension/openssl">TLS 插件</a> 后，之前不稳定的原因我终于找到了，这个后面再说。</p>
<p>先过一下 mnet 的插件系统，比如为什么要做成插件系统。</p>
<p>因为 mnet 本身是一个小型网络库，几乎是就是单文件支持 MacOS/Linux/FreeBSD/Windows，抽象了 epoll/kqueue/wepoll (IOCP epoll 化)，将 TLS 做成插件，是希望没有编译链接 TLS、OpenSSL 时，仍能独立支持 TCP、UDP。而加入 TLS、OpenSSL 的插件代码，以及相关编译选项后，提供 TLS 的支持，使用方式跟抽象为 chann 的普通 TCP 一样。</p>
<p>为了达成这一个目标，mnet 将插件接口抽象为基于 chann_type 的一种配置，mnet_core 单文件本身就提供了 TCP、UDP 的内建插件，外部只需要在 open_chann 时指定使用 TCP、UDP 接口，就能使用 core 提供的 chann listen、connect、send、recv API。</p>
<p>TLS 插件则是抽象 TLS 为一种外部定义的 chann_type，配置了这个定义后，TLS chann 使用方式跟 TCP、UDP 没有差别，从内部往外看，TLS chann_type 也是一种普通的 chann 而已，内部 core 对于所有类型的 chann_type，都提供同样能力的配置接口，没有特别对待。</p>
<p>所谓插件配置，其实就是抽象了 open_chann，listen_chann/connect_chann, send_chann/recv_chann, disconnect_chann/close_chann，chann_state 的回调函数，mnet 的插件，只要能提供 fd，以及这些插件接口，就可以利用上内部的 epoll、kqueue，以及 sending cache。</p>
<p>这样，外部建立 TLS chann，只需要指定 TLS chann_type，open 后做 listen/connect 就好，插件需要外部提供 SSL_CTX，因此证书管理是在外部的，网络无关的 API 内部没有引入。插件提供了 filter 接口，对于 epoll/kqueue 的读写事件，会 filter 询问 chann_type 对应的插件接口，是否要传递给外层调用的 API，还是插件还需要继续处理。</p>
<p>插件同样封装了 chann_state，这样 TLS 的状态可以有 CLOSE/DISCONNECT/CONNECTING/CONNECTED/LISTEN 了。</p>
<p>接着说一下之前在 Lua/LuaJIT 层为何基于 mnet 的 TCP 层做 SSL 没成功，仔细阅读 SSL_read/SSL_write 的 man page，可以看到这个接口接收到 buffer 读写命令后，底层仍然可能有重协商的逻辑，重协商的逻辑需要双方的数据传递，因此有可能需要先读取数据（协商相关的数据）才能写 buffer，反观 SSL_read 底层的重协商有可能先要写数据，才能读。</p>
<p>SSL_read/SSL_write 都有可能导致底层重协商，如果 fd 是阻塞的，协商结束，数据读、写成功后，才会返回给调用方；如果是非阻塞的 fd，ret 返回 &lt;= 0，需要调用 SSL_get_error(ret) 来获取是否是 SSL_ERROR_WANT_READ 或者 SSL_ERROR_WANT_WRITE，还是确实出错了，比如 SSL_ERROR_SSL 这种错误只有 SSL_shutdown，然后 close(fd) 了。</p>
<p>非阻塞 fd 导致的 WANT_READ 或 WANT_WRITE 的错误，需要调用方在合适的时机，使用同样的参数重新调用。说实话，看到这里，我总觉得这个 API 怎能这样设计，但是从 API 提供者的角度来说，非阻塞的 fd，需要打包额数据也许不足 ，也许干嘛干嘛，反正需要等待双方协商好后才能重新打包，如果传递过来的不是之前的数据，或者长度，又需要重新协商了。</p>
<p>为了方便调用方，SSL 提供了两个改善性的配置，一个是 SSL_MODE_ENABLE_PARTIAL_WRITE，只写一部分数据成功后，也返回了，再次发起 SSL_write 可以传递新的数据了，而不是整个 buffer 都成功才返回；另外一个是 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER，意味着调用方可以换用 buffer 指针（内容、长度还需一致）。</p>
<p>之前 mnet 的 send 是有 cache 的，cache 长度是固定的，导致上面 SSL_write 这个接口不满足，长度变了，这次为了支持 TLS，一旦有 send 数据 cache，都是申请足量的内存 cache 住，后续 epoll/kqueue raise 了可以写的事件，在传递同样的内容、长度（仅 buffer 指针变化）给插件层的 send。</p>
<p>以上就解决了之前 Lua/LuaJIT SSL 不稳定的问题。</p>
<p>我自己是搞了自签名的证书、私钥测试了 reconnect 和 rwdata 这两个跟 TCP 一样的单点测试程序，算是通过了验收。因为 SSL_CTX 是外部提供的，因此后续的认证问题，应该不是问题，即便有特殊需要，基于插件的系统，应该可以可以回调解决吧，毕竟其实我也没有很重度使用这个插件的功能呢。</p>
<p>先这样吧。</p>
<div class="category"><a href="CategoryProgramming.html">CategoryProgramming</a> / <a href="2022-02.html#p1">Permalink</a> / <a href="https://github.com/lalawue/homepage/discussions/categories/blog" target="_blank">Discussion</a></div>
<p><a id="p0"></a></p>
<div class="date">22年2月10日 周二 00:56</div>
<h2>LuaRocks with LuaJIT (2)</h2>
<p>之前我还提到<a href="../blog/2020-07.html#p3">使用了 torch 的 LuaRock 方案</a>，但实际上不晓得 LuaRocks 在哪个版本起（至少在 3.7），编译的时候指定 Lua 解释器，就能直接支持，我其实已经用上很长时间了。</p>
<p>说实话，比较期待 LuaRocks 的方面是，直接根据依赖的 rocks，能够输出 single executable，虽然按照目前 LuaRocks 的 spec 构建描述，应该是很难的。</p>
<div class="category"><a href="CategoryProgramming.html">CategoryProgramming</a> / <a href="2022-02.html#p0">Permalink</a> / <a href="https://github.com/lalawue/homepage/discussions/categories/blog" target="_blank">Discussion</a></div>
<!-- Page published by cmark-gfm ends here -->
  <div id="foot">2004-<script>var d = new
	Date();document.write(d.getFullYear())</script> &copy;
	Sucha. Powered by MarkdownProjectCompositor.
  </div>
  </div><!-- text -->
  <div id="sidebar">
  </div><!-- sidebar -->
  <script src="../js/prism.min.js" async="async"></script>
  <script src="../js/blog_sidebar.js"></script>
  </div> <!-- body -->
</body>
</html>